import docsImg1 from '@/assets/img/docs/docs01.jpg';
import docsImg2 from '@/assets/img/docs/docs02.jpg';
import docsImg3 from '@/assets/img/docs/docs03.jpg';
import docsImg4 from '@/assets/img/docs/docs04.jpg';
import docsImg5 from '@/assets/img/docs/docs05.jpg';
import docsImg6 from '@/assets/img/docs/docs06.jpg';
import docsImg7 from '@/assets/img/docs/docs07.jpg';
import MarkDown from '@/components/MarkDown';
import TopFooter from '@/components/TopFooter';
import { ftBlog } from '@/service/modules/home';
import React, { memo, useEffect, useState } from 'react';
import { useLocation } from 'umi';
import './index.less';

interface Iprops {}
const DOCS: React.FC<Iprops> = (props) => {
  const location = useLocation();
  const [docsDesc, setDocsDesc] = useState<any>({
    id: 1,
    title: 'um4使用手册',
    tags: ['um4', '使用手册', 'react'],
    content:
      "## 官网\n\nhttps://umijs.org/docs/introduce/introduce\n\n## 安装\n\n```shell\nnpx create-umi@latest\n```\n\n选择模板： Simple App\n\n如果需要安装max版本，可以选择ant design 模板\n\n## 环境变量\n\n.env文件，有三种类型环境配置内容\n\n```shell\n# 一些公用的配置\nPORT=8888 # 启动端口\nDID_YOU_KNOW=none # 关闭构建时候的你知道吗...\n\n# node构建时参数\nXXX=none\n\n# node运行时，需要配置UMI_APP开头\nUMI_APP_XXX=777\n```\n\n```shell\n// 获取配置内容\nprocess.env.XXX\n```\n\n## 全局脚本和样式和运行时配置\n\n```tsx\n// /src/global.tsx\n// 全局前置脚本文件\nconsole.log(\"前置脚本执行成功\");\n```\n\n```less\n// /src/global.less\nbody {\n  background: #eee;\n}\n\n.global-loading {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background-color: rgba(255, 255, 255, 0.8);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  z-index: 9999;\n\n  .spinner {\n    border: 4px solid #f3f3f3;\n    border-top: 4px solid #ff4d6a;\n    border-radius: 50%;\n    width: 40px;\n    height: 40px;\n    animation: spin 1s linear infinite;\n    margin-right: 10px;\n  }\n\n  p {\n    font-size: 16px;\n    color: #333;\n  }\n}\n\n@keyframes spin {\n  0% {\n    transform: rotate(0deg);\n  }\n  100% {\n    transform: rotate(360deg);\n  }\n}\n\n```\n\n```jsx\n// app.tsx\n// 运行时配置代码完成\nconsole.log(\"运行时配置代码完成\");\n```\n\n## 公共页面加载\n\num4的通过页面分包，所以新进的页面需要重新加载各种js文件，所以要加个页面加载比较好\n\n```tsx\n// loading.tsx\nimport React from \"react\";\n\nconst Loading: React.FC = () => {\n  return (\n    <div className=\"global-loading\">\n      <div className=\"spinner\"></div>\n      <p>加载中...</p>\n    </div>\n  );\n};\n\nexport default Loading;\n\n```\n\n## 引入prettier\n\numi提供了[代码生成器](https://umijs.org/docs/guides/generator#prettier-%E9%85%8D%E7%BD%AE%E7%94%9F%E6%88%90%E5%99%A8)，直接生成\n\n```shell\nnpx umi g prettier\n```\n\n## 引入eslint\n\numi也提供了专门的包\n\n```shell\npnpm add @umijs/lint -D\npnpm add -D eslint \"stylelint@^14\"\n```\n\n```js\n// .eslintrc.js\nmodule.exports = {\n  // Umi 项目\n  extends: require.resolve('umi/eslint'),\n}\n```\n\n```json\n// package.json\n\"lint\": \"umi lint\",\n```\n\n\n\n## 路由\n\numi提供了layouts页面，全局页面方便使用\n用`<Outlet />` 渲染嵌套路由\n\n```tsx\n// layouts/index.tsx\nimport { Link, Outlet } from \"umi\";\nimport styles from \"./index.less\";\n\nexport default function Layout() {\n  return (\n    <div className={styles.navs}>\n      <ul className=\"navnav\">\n        <li>\n          <Link to=\"/\">Home</Link>\n        </li>\n        <li>\n          <Link to=\"/docs\">Docs</Link>\n        </li>\n      </ul>\n      <Outlet />\n    </div>\n  );\n}\n```\n\n**如果没有 routes 配置，Umi 会进入约定式路由模式**，然后分析 `src/pages` 目录拿到路由配置。\n\n路由设置的话，**建议拆分路由**\n\n```tsx\n//routes/index.tsx\nconst routes: any[] = [\n  {\n    path: \"/\",\n    component: \"home\",\n  },\n  {\n    path: \"/docs\",\n    component: \"docs\",\n  },\n  {\n    path: \"/test1\",\n    component: \"test1\",\n  },\n];\n\nexport default routes;\n\n```\n\n```ts\n//.umirc.ts\nimport routes from \"./src/routes\";\nexport default defineConfig({\n  routes,\n});\n```\n\n**跳出layout页面的路由设置**\n\n```jsx\n// src/routes/index\n{\n    path: \"/login\",\n    component: \"login\",\n    layout: false,\n  },\n```\n\n**路由拦截**\n\n```tsx\n// src/wrappers/auth\nimport { Navigate, Outlet } from \"umi\";\n\nexport default () => {\n  // const { isLogin } = useAuth();\n  console.log(\"判断是否登录\");\n  const isLogin = true;\n  if (isLogin) {\n    return <Outlet />;\n  } else {\n    return <Navigate to=\"/login\" />;\n  }\n};\n```\n\n```tsx\n  // src/routes/index\n  {\n    path: \"/user\",\n    component: \"user\",\n    wrappers: [\"@/wrappers/auth\"],\n  },\n  {\n    path: \"/login\",\n    component: \"login\",\n    layout: false,\n  },\n```\n\n\n\n## 封装网络请求\n\n安装axios，用封装好的文件即可\n\n\n\n## 重要插件包\n\n```shell\npnpm add -D @umijs/plugins\n```\n\n## 引入antd\n\n需要安装antd，也要配置@umijs/plugins/dist/antd，那它们的区别是什么呢？\n\nantd安装放出来自由安装，是给你随时换版本和按需加载组件\n\n插件的配置主要是优化对这个antd的一些配置简单化\n\n```shell\npnpm i antd -S\n```\n\n```ts\n// .umirc.ts\nexport default {\n  plugins: [\"@umijs/plugins/dist/antd\"],\n  antd: {\n    dark: true, // 暗黑风格\n    theme: {\n      token: {\n        colorPrimary: \"#ff4d6a\", // 全局替换Primary颜色\n      },\n    },\n  },\n}\n```\n\n```tsx\n// index.tsx\nimport { Button } from \"antd\";\nconst DocsPage = () => {\n  return (\n    <div>\n      <p>This is umi docs.</p>\n      <Button type=\"primary\">Button</Button>\n    </div>\n  );\n};\n\nexport default DocsPage;\n```\n\n效果：\n\n![image-20250613102010617](.\\img\\image-20250613102010617.png)\n\n## 引入model\n\nuseModel就是状态管理，官方推荐的用来替代dva的传统方法\n\n这个完全就是umi内置的，只要设置好文件夹和配置，重新dev就好了\n\n可以全局models文件设置状态管理，也可以对应pages页面设置状态管理\n\n```ts\n// umirc.ts\nimport { defineConfig } from \"umi\";\nexport default defineConfig({\n  npmClient: \"pnpm\",\n  plugins: [\"@umijs/plugins/dist/model\"],\n  model: {},\n});\n```\n\n```ts\n// src/models/userModel.ts\nimport { useState } from 'react';\n\nexport default () => {\n  const [user, setUser] = useState({\n    name: 'user',\n    age: 18,\n    sex: 'male',\n  });\n  const [loading, setLoading] = useState(true);\n\n  return {\n    user,\n    loading,\n    setUser,\n    setLoading,\n  };\n};\n```\n\n```ts\n// src/pages/docs/model.ts\nexport default () => {\n  const docsData = {\n    username: 'umi',\n  };\n\n  return { docsData };\n};\n```\n\n```tsx\n// src/pages/docs/index.tsx\nimport { useModel } from 'umi';\n\nexport default () => {\n  const { user, setUser, loading, setLoading } = useModel('userModel');\n  const { docsData } = useModel('docs.model');\n  return (\n    <div>{user.name}{docsData.username}</div>\n  );\n};\n\n```\n\n减少渲染，可以引入第二个参数\n\n```ts\n// 只有name修改了，才会触发组件重新执行\nconst { name } = useModel('userModel', (e) => {\n    return {\n      name: e.user.name,\n    };\n  });\n```\n\n全局初始数据设置，也属于model不过是放到app.tsx中运行时执行,通常用来请求用户信息\n\n```tsx\n// src/app.tsx\nexport async function getInitialState() {\n  return {\n    userId: 1,\n    role: 'admin',\n  };\n}\n```\n\n```jsx\n  const { initialState } = useModel('@@initialState');\n```\n\n## 引入权限\n\n权限比较特殊，是需要用到model，initial-state来配合，而且**initial-state需要在model上面，不然就报错**\n\n```ts\n// umirc.ts\nimport { defineConfig } from 'umi';\nexport default defineConfig({\n  plugins: [\n    '@umijs/plugins/dist/initial-state',\n    '@umijs/plugins/dist/model',\n    '@umijs/plugins/dist/access',\n  ],\n  initialState: {},\n  model: {},\n  access: {},\n});\n```\n\n```tsx\n// src/app.tsx\nexport async function getInitialState() {\n  return {\n    userId: 1,\n    role: 'admin',\n  };\n}\n```\n\n```ts\n// src/access.ts\nexport default function (initialState: any) {\n  const { userId, role} = initialState;\n  return {\n    canReadFoo1: role === 'admin' ? true : false,\n    canReadFoo2: role === 'admin' ? false : true,\n  };\n}\n```\n\n**页面查看权限**\n\n```tsx\n// src/page/docs\nconst access = useAccess();\nconsole.log(access); \n\n {\n    \"canReadFoo1\": true,\n    \"canReadFoo2\": false\n}\n```\n\n**路由权限设置**\n\n把key设置到路由设置中，umi帮你过滤路由，前提是要跟layout插件配合\n\n```ts\n// umirc.ts\nimport { defineConfig } from 'umi';\nexport default defineConfig({\n  plugins: [\n    '@umijs/plugins/dist/layout',\n  ],\n  layout: {},\n});\n```\n\n```tsx\n// src/pages/403.tsx\nexport default () => {\n  return <div>403无权限</div>;\n};\n```\n\n```ts\n// src/routes/index.ts\nconst routes: any[] = [\n  {\n    path: '/',\n    component: 'home',\n  },\n  {\n    path: '/docs',\n    component: 'docs',\n    access: 'canReadFoo2',\n  },\n  { path: '/*', component: '@/pages/404' },\n];\n\nexport default routes;\n\n```\n\n```tsx\n// stc/app.tsx\nimport Page403 from '@/pages/403';\nimport { RunTimeLayoutConfig } from 'umi';\n\nexport const layout: RunTimeLayoutConfig = () => {\n  return {\n    // 自定义 403 页面\n    unAccessible: <Page403 />,\n  };\n};\n```\n\n![image-20250625160033597](.\\img\\image-20250625160033597.png)\n\n## 引入国际化\n\n引入locale插件\n\n```ts\nimport { defineConfig } from 'umi';\n\nexport default defineConfig({\n  plugins: [\n    '@umijs/plugins/dist/locale',\n  ],\n  locale: {\n    default: 'zh-CN',\n    baseSeparator: '-',\n  },\n});\n```\n\n```ts\n// src/locals/zh-CN.ts\nexport default {\n  welcome: '欢迎光临 Umi 的世界！',\n};\n```\n\n```ts\n// src/locals/zh-US.ts\nexport default {\n  welcome: \"Welcome to Umi's world!\",\n};\n```\n\n```tsx\n// 组件方式引入\n<FormattedMessage id=\"welcome\" />\n```\n\n```tsx\n// 代码方式引入\nimport { useIntl } from 'umi';\nconst intl = useIntl();\nconst msg = intl.formatMessage({\n    id: 'welcome',\n});\n```\n\n```ts\n// 切换语言\nimport { setLocale } from 'umi';\n// 切换时刷新页面\nsetLocale('zh-US');\n// 切换时不刷新页面\nsetLocale('zh-US', false);\n```\n\n## 引入dva\n\ndva和model的使用，二选一即可\n\n```ts\nimport { defineConfig } from 'umi';\n\nexport default defineConfig({\n  plugins: [\n    '@umijs/plugins/dist/dva',\n  ],\n  dva: {},\n});\n\n```\n\nmodels文件夹的逻辑也可以用到dva设置中，也是可以全局自动增加到store中\n\n```ts\n// src/models/homeModel\nimport { ftMenuData } from '@/service/modules/home';\nimport { Effect, Reducer } from 'umi';\n\nexport interface IHomeModelState {\n  menuData: any;\n}\nexport interface IHomeModelType {\n  state: IHomeModelState;\n  effects: {\n    queryMenu: Effect;\n  };\n  reducers: {\n    setState: Reducer<IHomeModelState>;\n  };\n}\n\nconst model: IHomeModelType = {\n  state: {\n    menuData: [],\n  },\n  effects: {\n    *queryMenu({}, { call, put }) {\n      // 使用接口\n      const { banner } = yield call(ftMenuData);\n      const { list } = banner;\n      yield put({\n        type: 'setState',\n        payload: {\n          menuData: list || [],\n        },\n      });\n    },\n  },\n  reducers: {\n    setState(state, { payload }) {\n      return {\n        ...state,\n        ...payload,\n      };\n    },\n  },\n};\n\nexport default model;\n```\n\n```tsx\n// src/pages/docx.tsx\nimport { useDispatch, useModel, useSelector, useStore } from 'umi';\nconst { menuData } = useSelector((state: any) => state.homeModel);\n  useEffect(() => {\n    dispatch({\n      type: 'homeModel/queryMenu',\n    });\n}, []);\n```\n\nstate的类型有两种方式，一种是反向推导，一种是自己设置\n\n```ts\n// type/store.ts\nimport { IHomeModelState } from '@/models/homeModel';\n\n// 自己设置\nexport interface RootState {\n  homeModel: IHomeModelState;\n}\n\n// 反向推到，但是使用无效\n// type RootState = ReturnType<(typeof $store)['getState']>;\n```\n\n```tsx\n// src/pages/docx.tsx\nimport { RootState } from '@/type/store';\nimport { useDispatch, useModel, useSelector, useStore } from 'umi';\nconst { menuData } = useSelector((state: RootState) => state.homeModel);\n  useEffect(() => {\n    dispatch({\n      type: 'homeModel/queryMenu',\n    });\n}, []);\n```\n\n## 引入mock\n\n不用配置插件，直接mock文件夹下配置\n\n```js\n// /mock/todo.ts\nexport default {\n  'GET /api1/todo': [\n    { id: 1, name: 'foo' },\n    { id: 2, name: 'bar' },\n  ],\n  'GET /api1/todo/1': { id: 1, name: 'foo' },\n};\n```\n\n```ts\n// umirc.ts\n  proxy: {\n    '/api1': {\n      target: 'http://codercba.com:8000',\n      changOrigin: true,\n      pathRewrite: {\n        '^/api1': '',\n      },\n    },\n  },\n```\n\n```ts\n// src/service/modules/home.ts\nexport const ftTodoList = () => {\n  return $api1.get<Imultidata>({\n    url: '/todo',\n  });\n};\n```\n\n![image-20250630151902890](.\\img\\image-20250630151902890.png)",
  });
  // 随机获取图片
  function getRandomImg() {
    const imgArr = [docsImg1, docsImg2, docsImg3, docsImg4, docsImg5, docsImg6, docsImg7];
    return imgArr[Math.floor(Math.random() * imgArr.length)];
  }

  useEffect(() => {
    document.documentElement.scrollTop = 0;
    if (location.state) {
      const { id } = location.state as any;
      if (id) {
        ftBlog(id).then((res) => {
          console.log(res);
          const { code, data, message } = res;
          if (code === 200) {
            const { id, title, tags, content } = data;
            setDocsDesc({
              id,
              title,
              tags,
              content,
            });
          }
        });
      }
    }
    console.log(location);
  }, []);

  return (
    <div className="docs-page">
      <div className="dp-imgcover">
        <img src={getRandomImg()} alt="docsImg1" />
        <span className="dpi-title">{docsDesc.title}</span>
      </div>
      <div className="dp-header wrapper-v2">
        <div className="dp-header-title">{docsDesc.title}</div>
        <div className="dp-header-tags">
          当前标签：
          {docsDesc.tags.map((tag: string, index: number) => (
            <span key={index} style={{ marginRight: 4 }}>{tag}</span>
          ))}
        </div>
      </div>
      <div className="docs-content wrapper-v2">
        <MarkDown content={docsDesc.content} />
      </div>
      <TopFooter></TopFooter>
    </div>
  );
};

export default memo(DOCS);
